﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using CoreEx.Common.Extensions;
using CoreEx.Services;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using LinFu.IoC;

namespace CoreEx.Common.Implementation.Ioc
{
    [Implements(typeof(IWeaveTargetLoader))]
    public class WeaveTargetLoader : IWeaveTargetLoader, IInitialize
    {
        private IServiceContainer _serviceContainer;

            
        public void Load(IEnumerable<string> assemblyFiles)
        {
            AppDomain appDomain = CreateAppDomain();

            string assemblyName = GetType().Assembly.FullName;
            if (assemblyName == null)
                return; 

            var extractor = (WeaveTargetExtractor)appDomain.CreateInstanceAndUnwrap
                                                                                (assemblyName, typeof(WeaveTargetExtractor).FullName);
            
            var weaveTargets = extractor.GetWeaveTargets(assemblyFiles);

            Merge(weaveTargets);

            AppDomain.Unload(appDomain);            
        }


        protected virtual void Merge(IDictionary<string,IList<Type>> weaveTargets)
        {            
            var assemblyWeavers = _serviceContainer.GetService<IDictionary<string, IList<Type>>>("AssemblyWeavers");
            foreach (var weaveTarget in weaveTargets)
            {
                if (!assemblyWeavers.ContainsKey(weaveTarget.Key))                
                    assemblyWeavers.Add(weaveTarget.Key,new List<Type>());
                weaveTarget.Value.ForEach(t => assemblyWeavers[weaveTarget.Key].Add(t));
            }
        }



        /// <summary>
        /// Creates a new <see cref="AppDomain"/>
        /// </summary>
        /// <returns>A new <see cref="AppDomain"/></returns>
        private static AppDomain CreateAppDomain()
        {
            AppDomainSetup setup = new AppDomainSetup();
            //setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
            setup.ApplicationBase = Path.GetDirectoryName(new Uri(typeof(WeaveTargetLoader).Assembly.CodeBase).LocalPath);
            setup.DisallowBindingRedirects = false;
            setup.DisallowCodeDownload = true;
            setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
            AppDomain appDomain = AppDomain.CreateDomain("appDomain", null, setup);
            return appDomain;
        }

        public void Initialize(IServiceContainer source)
        {
            _serviceContainer = source;

            //Make sure that the AssemblyWeavers service is registered in the container.
            if (!_serviceContainer.Contains("AssemblyWeavers",typeof(IDictionary<string, IList<Type>>)))
                _serviceContainer.AddService("AssemblyWeavers", typeof(IDictionary<string, IList<Type>>),
                   new Dictionary<string, IList<Type>>());
        }
    }
}